<?php
/*
 File: xajaxScriptPlugin.inc.php

Contains the xajaxScriptPlugin class declaration.

Title: xajaxScriptPlugin class

Please see <copyright.inc.php> for a detailed description, copyright
and license information.
*/

/*
 @package xajax
@version $Id: xajaxScriptPlugin.inc.php 362 2007-05-29 15:32:24Z calltoconstruct $
@copyright Copyright (c) 2005-2007 by Jared White & J. Max Wilson
@copyright Copyright (c) 2008-2010 by Joseph Woolley, Steffen Konerow, Jared White  & J. Max Wilson
@license http://www.xajaxproject.org/bsd_license.txt BSD License
*/

/*
 Class: xajaxScriptPlugin

Contains the code that can produce script and style data during deferred script
generation.  This allows the xajax generated javascript and style sheet information
to be loaded via an external file reference instead of inlined into the page
source.
*/
class xajaxScriptPlugin extends xajaxRequestPlugin
{
	/*
		String: sRequest
	*/
	var $sRequest;

	/*
		String: sHash
	*/
	var $sHash;

	/*
		String: sRequestURI
	*/
	var $sRequestURI;

	/*
		Boolean: bDeferScriptGeneration
	*/
	var $bDeferScriptGeneration;

	/*
		Boolean: bValidateHash
	*/
	var $bValidateHash;

	/*
		Boolean: bWorking
	*/
	var $bWorking;

	/*
		Function: xajaxScriptPlugin

	Construct and initialize the xajax script plugin object.  During
	initialization, this plugin will look for hash codes in the
	GET data (parameters passed on the request URI) and store them
	for later use.
	*/
	function xajaxScriptPlugin()
	{
		$this->sRequestURI = '';
		$this->bDeferScriptGeneration = false;
		$this->bValidateHash = true;

		$this->bWorking = false;

		$this->sRequest = '';
		$this->sHash = null;

		if (isset($_GET['xjxGenerateJavascript'])) {
			$this->sRequest = 'script';
			$this->sHash = $_GET['xjxGenerateJavascript'];
		}

		if (isset($_GET['xjxGenerateStyle'])) {
			$this->sRequest = 'style';
			$this->sHash = $_GET['xjxGenerateStyle'];
		}
	}

	/*
		Function: configure

	Sets/stores configuration options used by this plugin.  See also:
	<xajax::configure>.  This plugin will watch for and store the current
	setting for the following configuration options:

	- <requestURI> (string): The requestURI of the current script file.
	- <deferScriptGeneration> (boolean): A flag that indicates whether
	script deferral is in effect or not.
	- <deferScriptValidateHash> (boolean): A flag that indicates whether
	or not the script hash should be validated.
	*/
	function configure($sName, $mValue)
	{
		if ('requestURI' == $sName) {
			$this->sRequestURI = $mValue;
		} else if ('deferScriptGeneration' == $sName) {
			if (true === $mValue || false === $mValue)
				$this->bDeferScriptGeneration = $mValue;
		} else if ('deferScriptValidateHash' == $sName) {
			if (true === $mValue || false === $mValue)
				$this->bValidateHash = $mValue;
		}
	}

	/*
		Function: generateClientScript

	Called by the <xajaxPluginManager> when the text of the client script
	(or style) declarations are needed.

	This function will only output script or style information if the
	request URI contained an appropriate hash code and script deferral
	is in effect.
	*/
	function generateClientScript()
	{
		if ($this->bWorking)
			return;

		if (true === $this->bDeferScriptGeneration)
		{
			$this->bWorking = true;
				
			$sQueryBase = '?';
			if (0 < strpos($this->sRequestURI, '?'))
				$sQueryBase = '&';
				
			$aScripts = $this->_getSections('script');
			if (0 < count($aScripts))
			{
				//				echo "<!--" . print_r($aScripts, true) . "-->";
					
				$sHash = md5(implode($aScripts));
				$sQuery = $sQueryBase . "xjxGenerateJavascript=" . $sHash;

				echo "\n<script type='text/javascript' src='" . $this->sRequestURI . $sQuery . "' charset='UTF-8'></script>\n";
			}
				
			$aStyles = $this->_getSections('style');
			if (0 < count($aStyles))
			{
				//				echo "<!--" . print_r($aStyles, true) . "-->";
					
				$sHash = md5(implode($aStyles));
				$sQuery = $sQueryBase . "xjxGenerateStyle=" . $sHash;

				echo "\n<link href='" . $this->sRequestURI . $sQuery . "' rel='Stylesheet' />\n";
			}
				
			$this->bWorking = false;
		}
	}

	/*
		Function: canProcessRequest

	Called by the <xajaxPluginManager> to determine if this plugin can
	process the current request.  This will return true when the
	requestURI contains an appropriate hash code.
	*/
	function canProcessRequest()
	{
		return ('' != $this->sRequest);
	}

	function _getSections($sType)
	{
		$objPluginManager = xajaxPluginManager::getInstance();

		$objPluginManager->configure('deferScriptGeneration', 'deferred');

		$aSections = array();

		// buffer output

		ob_start();
		$objPluginManager->generateClientScript();
		$sScript = ob_get_clean();

		// parse out blocks

		$aParts = explode('</' . $sType . '>', $sScript);
		foreach ($aParts as $sPart)
		{
			$aValues = explode('<' . $sType, $sPart, 2);
			if (2 == count($aValues))
			{
				list($sJunk, $sPart) = $aValues;

				$aValues = explode('>', $sPart, 2);
				if (2 == count($aValues))
				{
					list($sJunk, $sPart) = $aValues;
						
					if (0 < strlen($sPart))
						$aSections[] = $sPart;
				}
			}
		}

		$objPluginManager->configure('deferScriptGeneration', $this->bDeferScriptGeneration);

		return $aSections;
	}

	/*
		Function: processRequest

	Called by the <xajaxPluginManager> when the current request should be
	processed.  This plugin will generate the javascript or style sheet information
	that would normally be output by the other xajax plugin objects, when script
	deferral is in effect.  If script deferral is disabled, this function returns
	without performing any functions.
	*/
	function processRequest()
	{
		if ($this->canProcessRequest())
		{
			$aSections = $this->_getSections($this->sRequest);
				
			//			echo "<!--" . print_r($aSections, true) . "-->";
				
			// validate the hash
			$sHash = md5(implode($aSections));
			if (false == $this->bValidateHash || $sHash == $this->sHash)
			{
				$sType = 'text/javascript';
				if ('style' == $this->sRequest)
					$sType = 'text/css';
					
				$objResponse = new xajaxCustomResponse($sType);

				foreach ($aSections as $sSection)
					$objResponse->append($sSection . "\n");

				$objResponseManager = xajaxResponseManager::getInstance();
				$objResponseManager->append($objResponse);

				header ('Expires: ' . gmdate('D, d M Y H:i:s', time() + (60*60*24)) . ' GMT');

				return true;
			}
				
			return 'Invalid script or style request.';
			trigger_error('Hash mismatch: ' . $this->sRequest . ': ' . $sHash . ' <==> ' . $this->sHash, E_USER_ERROR);
		}
	}
}

/*
 Register the plugin with the xajax plugin manager.
*/
$objPluginManager = xajaxPluginManager::getInstance();
$objPluginManager->registerPlugin(new xajaxScriptPlugin(), 9999);
